package us.gaaoc.framework.webapp.backingbeans.clerk;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectItem;
import javax.faces.component.html.HtmlSelectOneListbox;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.faces.validator.ValidatorException;

import com.lowagie.text.Image;

import org.apache.log4j.Logger;

import us.gaaoc.cms.Exporter;
import us.gaaoc.cms.Importer;
import us.gaaoc.cms.sustain.vo.CaseDocument;
import us.gaaoc.cms.sustain.vo.CaseFiling;
import us.gaaoc.framework.model.CaseRecord;
import us.gaaoc.framework.model.CaseRecordStatus;
import us.gaaoc.framework.model.Court;
import us.gaaoc.framework.model.DocumentLocalCode;
import us.gaaoc.framework.model.DocumentStatus;
import us.gaaoc.framework.model.Documents;
import us.gaaoc.framework.model.LdapDirectoryPerson;
import us.gaaoc.framework.model.Person;
import us.gaaoc.framework.model.VisualMark;
import us.gaaoc.framework.model.VisualMarkCategory;
import us.gaaoc.framework.signature.digital.ldap.LdapClient;
import us.gaaoc.framework.signature.visual.DocumentStamping;
import us.gaaoc.framework.signature.visual.PDFStamper;
import us.gaaoc.framework.signature.visual.PDFStamperController;
import us.gaaoc.framework.util.CaseFilingPersistor;
import us.gaaoc.framework.util.DomToSustainConverter;
import us.gaaoc.framework.webapp.backingbeans.BaseBackingBean;
import us.gaaoc.framework.webapp.util.Messages;

/**
 * @author Michael Alexandrou
 * December 27th, 2007
 */
@SuppressWarnings("unchecked")
public class OperationsPage extends BaseBackingBean {
	
	/* **************** *
	 * Global Variables * 
	 * **************** */
	private static final long serialVersionUID = 1L;
	private String docketID;
	private String divisionID;
	private String docLocalCode;
	private Date stampDate;
	private FacesMessage message;
	private HtmlSelectOneListbox  docLocalCodeUI;
	private CaseRecord caseRecord;
	private List<DocumentLocalCode> docLocalCodeList = new ArrayList<DocumentLocalCode>();
	private static transient Logger LOG = Logger.getLogger(OperationsPage.class);
	private boolean renderDocImporterMessage = false;
	private Documents docWithCourtReceivedStamp = new Documents();
	private Documents docWithDocketIdStamp = new Documents();
	
	private String courtUuid;
	
	public OperationsPage() {
		Map sessionMap = this.getFacesContext().getExternalContext().getSessionMap();
		String caseUuid = (String)sessionMap.get("caseUuid");
		courtUuid = (String) sessionMap.get("courtUuid");
		CaseRecord caseRecord = this.getModelFacade().findCaseRecordById(caseUuid, courtUuid);
		this.caseRecord = caseRecord;
		//Get the list of all document instances of the case record
		List<Integer> docInstanceCodeList = new ArrayList<Integer>();
		docInstanceCodeList = this.getDocumentInstanceCodeList(caseRecord);
		this.docLocalCodeUI = new HtmlSelectOneListbox();
		for(Integer docInstanceCode :docInstanceCodeList){
			//For each of the document instances get corresponding local codes 			
			//and document titles and use these pairs of local codes and corresponding document titles
			//as objects and labels to create UISelectItem uiItems to populate the list box
			int documentInstanceCode = docInstanceCode.intValue();
			DocumentLocalCode docLocalCode = this.getModelFacade().findDocumentLocalCodeFromDocumentInstanceCode(documentInstanceCode);	
			this.docLocalCodeList.add(docLocalCode);
			SelectItem item = new SelectItem(docLocalCode.getCode(), (this.getDocumentFromLocalInstanceCode(caseRecord, new Integer(docLocalCode.getCode()).intValue())).getTitle());
			UISelectItem uiItem = new UISelectItem();
			uiItem.setValue(item);
			this.docLocalCodeUI.getChildren().add(uiItem);
		}
		
	}

	/**
	 * @return the divisionID
	 */
	public String getDivisionID() {
		return divisionID;
	}

	/**
	 * @param divisionID the divisionID to set
	 */
	public void setDivisionID(String divisionID) {
		this.divisionID = divisionID;
	}

	/**
	 * @return the docketID
	 */
	public String getDocketID() {
		return docketID;
	}

	/**
	 * @param docketID the docketID to set
	 */
	public void setDocketID(String docketID) {
		this.docketID = docketID;
	}

	/**
	 * @return the message
	 */
	public FacesMessage getMessage() {
		return message;
	}

	/**
	 * @param message the message to set
	 */
	public void setMessage(FacesMessage message) {
		this.message = message;
	}
	/**
	 * This method is used to add to an existing filing 
	 * @param docketID
	 * @param casDivID
	 * @throws Exception 
	 */
	public String pullCaseFromSustain( ) throws Exception {
		
		throw new UnsupportedOperationException("Can't pull cases from SUSTAIN");
		
		/*
		String casDivID;
		casDivID = this.divisionID;
	
		Map sessionMap = this.getFacesContext().getExternalContext().getSessionMap();
		String courtUuid = (String) sessionMap.get("courtUuid");
		Court court = this.getModelFacade().findCourt(courtUuid);
		
		boolean validDocketId = this.isValidDocketID(docketID);
		if(validDocketId){
			CaseRecord cr = new CaseRecord();
			// First look for case in GAJE database
			if(casDivID.equalsIgnoreCase("14")){		
				cr = this.getModelFacade().findCaseRecordByDocketID(docketID, courtUuid);
			}else if(casDivID.equalsIgnoreCase("12")){
				cr = this.getModelFacade().findCaseRecordByDocketID(docketID, courtUuid);
			}
			if(cr != null){
				CaseRecordStatus crs = this.getModelFacade().findCaseRecordStatusByCode(15);
				this.getModelFacade().updateCaseRecordStatus(cr.getUuid(), crs, courtUuid);
				// b7006e6c-695c-11dd-945f-00301b45ff56
				HibernatePhaseListener.getSessionFactory().getCurrentSession().getTransaction().commit();
				
			}else{				
			//If not in GAJE system, look in Court's Case Management System
				Exporter export = new Exporter(courtUuid);
				CaseFiling filing = export.doExport(docketID, casDivID,courtUuid,"clerkUuid3");
				if(filing !=null){
					CaseFilingPersistor cfp = new CaseFilingPersistor();
					
					cfp.saveToDataModel(filing, court);
					// b7006e6c-695c-11dd-945f-00301b45ff56
					HibernatePhaseListener.getSessionFactory().getCurrentSession().getTransaction().commit();
				}else {
					FacesContext facesContext = FacesContext.getCurrentInstance();
					facesContext.addMessage("existingFile:docketID", new FacesMessage("No case found in court's cms"));
					return "stay";
				}
			}
		}else {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			facesContext.addMessage("existingFile:docketID", new FacesMessage(" Invalid docketId format. Please enter a valid one!"));
			return "stay";
		}
		
		
		 DivisionId for BibbCounty is 14
		 * and for Washington County is 12 
		 * Search in our mysql database  for the given docketID 
		 * if it is there then change status to "unsentAddition" and show this filing under progressingFiling's table
		 * 
		 * if it is not there then call Angela's sustain method
		 * 
		 * change the status of the documents to "import" after imported into Sustain.
		 
		 
		return "childEnforcementCaseTypePage";
		*/
	}
	
	public String stampADocumentFromSustainWithCourtReceivedStamp() throws Exception{
		LOG.info("The stamping of the document begins");
		PDFStamper addStamp = new PDFStamper();
		Map sessionMap = this.getFacesContext().getExternalContext()
		.getSessionMap();
		String courtUuid = (String) sessionMap.get("courtUuid");
		Court court = this.getModelFacade().findCourt(courtUuid);
		
		CaseFiling caseFiling = DomToSustainConverter.createCaseFiling(this.getModelFacade(),this.caseRecord, court);
		
		
		if (this.divisionID.equalsIgnoreCase("14")) {}
		else if (this.divisionID.equalsIgnoreCase("12")) {}
		else {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			facesContext
					.addMessage("courtReceivedStampForm:divID",
							new FacesMessage(
									" Invalid divID. Please enter a valid one"));
			return "stay";
		}
		if (this.caseRecord != null) {
			LOG
					.info("There is a case record in GAJE system with case recoed uuid "
							+ caseRecord.getUuid());
			// LOG.info("The local code selected is
			// "+this.getDocLocalCode().toString());
			Documents docToStamp = null;
			for (DocumentLocalCode docLocalCode : this.docLocalCodeList) {
				if (this.docLocalCodeUI.getValue().equals(
						docLocalCode.getCode())) {					
					LOG.info("document to be stamped is "
							+ docLocalCode.getCode().toString());
					int intDocLocalCode = new Integer(this.docLocalCodeUI.getValue().toString()).intValue();
					docToStamp = getDocumentFromLocalInstanceCode(caseRecord, intDocLocalCode);
					Image sigIndicatorImage = getSigIndicatorImageOfLoggedPerson();
					int visualCode = 3; //for court stamp
					Person personSigner = (Person)this.getFacesContext().getExternalContext().getSessionMap().get("person");
					boolean courtStampFlag = true;
					VisualMarkCategory visualCategory = this.getModelFacade().getVisualCategory(visualCode);
					VisualMark visualMark = this.getModelFacade().getVisualMark(personSigner, courtStampFlag, visualCategory);
					String stampTarget =visualMark.getVisualTarget();
					if (docToStamp != null) {
						byte[] newDocContent = addStamp
								.AddCourtStamp(docToStamp, sigIndicatorImage,
										docToStamp.getReceivedDateTime(), court
												.getUuid(),stampTarget);
						if (newDocContent != null) {
							docToStamp.setContent(null,newDocContent);
							// create a caseDocument from the docToStamp
							// in order to import to cms
							CaseDocument pdfDoc = new CaseDocument();
							DocumentStamping docStamping = new DocumentStamping();
							pdfDoc = docStamping
									.createCaseDocumentFromDocument(docToStamp);
							//get the number of already imported documents
							int countOfAlreadyImportedDocs = this.getModelFacade().findTheNumberOfDocumentsAlreadyImportedIntoCMSOfACaseRecord(caseRecord);
							Importer importer = new Importer(courtUuid);
							LOG.info("***************************************************************************");
							LOG.info("The import process of newly court received stamped document is about to take place !");
							LOG.info("***************************************************************************");
							importer.importADocument(caseFiling, pdfDoc, this.divisionID,
									caseRecord.getCaseTrackingId(), docToStamp
											.getReceivedDateTime(), countOfAlreadyImportedDocs);
											//this.getCaseRecord().getCourt().getId(), "clerkUuid5");
							DocumentStatus ds = new DocumentStatus();
							ds.setCode(2);
							ds.setDescription("imported");
							docToStamp.setStatus(ds);
							this.renderDocImporterMessage = true;
							this.docWithCourtReceivedStamp = docToStamp;
							System.out
									.println("After the application of the stamp the status of the pdf document "
											+ docToStamp.getTitle()
											+ " is "
											+ docToStamp.getStatus().getCode());
						}
					} else {
						FacesContext facesContext = FacesContext
								.getCurrentInstance();
						facesContext
								.addMessage(
										"courtReceivedStampForm:courtReceivedStampADocumentFromSustainID",
										new FacesMessage(
												" Invalid document local code! Please enter a valid one"));
						return "stay";
					}
				}
			}

		} else {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			facesContext.addMessage("courtReceivedStampForm:stampADocumentFromSustainWithCourtReceivedStamp",
					new FacesMessage("Case exists in cms but the application doesn't recognize said case"));
			return "stay";

		}
		//return "childEnforcementCaseTypePage";
		return "stay";
	
	}
	
	
	
	public String stampADocumentFromSustainWithDocketIdStamp() throws Exception{
		LOG.info("The stamping of the document begins");
		PDFStamperController pdfStamperController = new PDFStamperController();
		Map sessionMap = this.getFacesContext().getExternalContext()
			.getSessionMap();
		Person personSigner = (Person) sessionMap.get("person");
		String courtUuid = (String) sessionMap.get("courtUuid");
		if (this.divisionID.equalsIgnoreCase("14")) {}
		else if (this.divisionID.equalsIgnoreCase("12")) {}
		else {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			facesContext
					.addMessage("courtReceivedStampForm:divID",
							new FacesMessage(
									" Invalid divID. Please enter a valid one"));
			return "stay";
		}
		if (this.caseRecord != null) {
			LOG
					.info("There is a case record in GAJE system with case recoed uuid "
							+ caseRecord.getUuid());
			// LOG.info("The local code selected is
			// "+this.getDocLocalCode().toString());
			Court c = this.getModelFacade().findCourt(courtUuid);
			CaseFiling caseFiling = DomToSustainConverter.createCaseFiling(this.getModelFacade(), this.caseRecord, c);
			Documents docToStamp = null;
			for (DocumentLocalCode docLocalCode : this.docLocalCodeList) {
				if (this.docLocalCodeUI.getValue().equals(
						docLocalCode.getCode())) {					
					LOG.info("document to be stamped is "
							+ docLocalCode.getCode().toString());
					int intDocLocalCode = new Integer(this.docLocalCodeUI.getValue().toString()).intValue();
					docToStamp = getDocumentFromLocalInstanceCode(caseRecord, intDocLocalCode);
					
					if (docToStamp != null) {
						pdfStamperController.applyDocketIdStampOnOneDoc(docToStamp, caseRecord.getCaseTrackingId(),personSigner);
						if(docToStamp.getContent() != null) {
						//if (newDocContent != null) {
							//docToStamp.setContent(newDocContent);
							// create a caseDocument from the docToStamp
							// in order to import to cms
							CaseDocument pdfDoc = new CaseDocument();
							DocumentStamping docStamping = new DocumentStamping();
							pdfDoc = docStamping.createCaseDocumentFromDocument(docToStamp);
							//get the number of already imported documents
							int countOfAlreadyImportedDocs = this.getModelFacade().findTheNumberOfDocumentsAlreadyImportedIntoCMSOfACaseRecord(caseRecord);
							Importer importer = new Importer(courtUuid);
							LOG.info("***************************************************************************");
							LOG.info("The import process of newly docket id stamped document is about to take place !");
							LOG.info("***************************************************************************");
							importer.importADocument(caseFiling,pdfDoc,this.divisionID,
									caseRecord.getCaseTrackingId(), docToStamp
											.getReceivedDateTime(), countOfAlreadyImportedDocs);
											//this.getCaseRecord().getCourt().getId(), "clerkUuid5");
							DocumentStatus ds = new DocumentStatus();
							ds.setCode(2);
							ds.setDescription("imported");
							docToStamp.setStatus(ds);
							this.renderDocImporterMessage = true;
							this.docWithDocketIdStamp = docToStamp;
							System.out
									.println("After the application of the stamp the status of the pdf document "
											+ docToStamp.getTitle()
											+ " is "
											+ docToStamp.getStatus().getCode());
						}
					} else {
						FacesContext facesContext = FacesContext
								.getCurrentInstance();
						facesContext
								.addMessage(
										"courtReceivedStampForm:courtReceivedStampADocumentFromSustainID",
										new FacesMessage(
												" Invalid document local code! Please enter a valid one"));
						return "stay";

					}
				}
			}

		} else {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			facesContext.addMessage("courtReceivedStampForm:stampADocumentFromSustainWithCourtReceivedStamp",
					new FacesMessage("Case exists in cms but the application doesn't recognize said case"));
			return "stay";

		}
		//return "childEnforcementCaseTypePage";
		return "stay";
	
	}
	
	
	
	
	/**
	 * This method validates the docketID entered by the User 
	 * @param context
	 * @param component
	 * @param value
	 * @throws ValidatorException
	 * @throws Exception
	 */
	public void validateDocketID(FacesContext context, UIComponent component,
			Object value) throws ValidatorException, Exception {
		String docketID = (String) value;
		if (!isValidDocketID(docketID.trim())) {
			message.setSeverity(FacesMessage.SEVERITY_ERROR);
			throw new ValidatorException(message);
		}
	}

	/**
	 * Helper method to validate the docketID entered by the user
	 * @param docketID
	 * @return
	 * @throws Exception
	 */
	protected boolean isValidDocketID(String docketID) throws Exception {
		boolean validField = false;
		char[] charArray = docketID.toCharArray();
		if (!(charArray.length > 10 || charArray.length < 9)) {
			for (char c : charArray) {
				if (!(Character.isDigit(c) || Character.isLetter(c))) {
					message = Messages.getMessage(
							"us.gaaoc.framework.webapp.util.errorMessage",
							"incorrectDocketID", new Object[] { docketID });
					message.setDetail(message.getDetail());
					message.setSeverity(FacesMessage.SEVERITY_ERROR);
					validField = false;
					break;
				} else
					validField = true;
			}
		} else {
			message = Messages.getMessage(
					"us.gaaoc.framework.webapp.util.errorMessage",
					"incorrectDocketID", new Object[] { docketID });
			message.setDetail(message.getDetail());
			message.setSeverity(FacesMessage.SEVERITY_ERROR);
		}
		return validField;
	}
	
	public String back() {
		return "backToCaseDetailsPage";
	}
	
	public String backToOperationsApplyCourtStampPage() {
		return "backToOperationsApplyCourtStampPage";
	}
	
	public String backToOperationsApplyDocketIdStampPage() {
		return "backToOperationsApplyDocketIdStampPage";
	}
	
	public Image getSigIndicatorImageOfLoggedPerson() {
		System.out.println("Inside the getSigIndicatorImageOfLoggedPerson method");
		Person personSigned = (Person) this.getFacesContext()
				.getExternalContext().getSessionMap().get("person");
		System.out.println("The person is "+personSigned.getFirstName()+", "+personSigned.getLastName());
		LdapDirectoryPerson ldapPerson = this.getModelFacade()
				.findLdapDirectoryByPerson(personSigned);
		String cnName = ldapPerson.getCname();
		LdapClient ldapClient = new LdapClient();
		Image sigIndicatorImage = ldapClient.retrieveSignatureImage(cnName);
		return sigIndicatorImage;
	}
	
	public List<Integer> getDocumentInstanceCodeList(CaseRecord caseRecord){
		List<Integer> docInstanceCodeList = new ArrayList<Integer>(); 		
		List<Documents> docList = caseRecord.getDocuments();
		for(Documents doc : docList){
			docInstanceCodeList.add(new Integer(doc.getDocumentInstance().getCode()));
		}
		return docInstanceCodeList;
	}
	/**
	 * Select from the Integer list of document instance codes a specific one
	 * @param documentInstanceCodeList
	 * @return docInstanceCode
	 */
	public int getDocumentInstanceCodeFromDocumentInstanceCodeList(List<Integer> documentInstanceCodeList, int docInstanceCodeToMatch){
		int docInstanceCode = -1;
		for(Integer intObject :documentInstanceCodeList){
			if(intObject.intValue() == docInstanceCodeToMatch);
			docInstanceCode = intObject.intValue();
		}
		return docInstanceCode;
	} 
	
	/**
	 * From the 
	 * @param documentInstanceCode
	 * @param courtUuid
	 * @return docLocalCode
	 */
	/*public int getDocLocalCodeFromDocumentInstanceCode(Integer documentInstanceCode, String courtUuid){
		DocumentLocalCode docLocalCode = this.ge
		int docLocalCode =  this.getModelFacade().getG-1;
		for(Integer intObject :documentInstanceCodeList){
			if(intObject.toString().equalsIgnoreCase(docLocalCode));
			docLocalCode = intObject.intValue();
		}
		return docLocalCode;
	} */
	
	public Documents getDocumentFromLocalInstanceCode(CaseRecord caseRecord, int docLocalCode){		
		Documents docToReturn = null;
		for(Documents doc : caseRecord.getDocuments()){
			int documentInstanceCode = doc.getDocumentInstance().getCode();
			DocumentLocalCode localInstanceCode = this.getModelFacade().findDocumentLocalCodeFromDocumentInstanceCode(documentInstanceCode);
			if(new Integer(localInstanceCode.getCode()).intValue() == docLocalCode){
				docToReturn = doc;
			}
		}
		return docToReturn;
	}

/*	public String getDocInstanceCode() {
		return docInstanceCode;
	}

	public void setDocInstanceCode(String docInstanceCode) {
		this.docInstanceCode = docInstanceCode;
	} */

	public Date getStampDate() {
		return stampDate;
	}

	public void setStampDate(Date stampDate) {
		this.stampDate = stampDate;
	}

	public String getDocLocalCode() {
		return docLocalCode;
	}

	public void setDocLocalCode(String docLocalCode) {
		this.docLocalCode = docLocalCode;
	}
	public CaseRecord getCaseRecord() {
		return caseRecord;
	}

	public void setCaseRecord(CaseRecord caseRecord) {
		this.caseRecord = caseRecord;
	}

	public HtmlSelectOneListbox getDocLocalCodeUI() {
		return docLocalCodeUI;
	}

	public void setDocLocalCodeUI(HtmlSelectOneListbox docLocalCodeUI) {
		this.docLocalCodeUI = docLocalCodeUI;
	}

	public boolean isRenderDocImporterMessage() {
		return renderDocImporterMessage;
	}

	public void setRenderDocImporterMessage(boolean renderDocImporterMessage) {
		this.renderDocImporterMessage = renderDocImporterMessage;
	}

	public Documents getDocWithCourtReceivedStamp() {
		return docWithCourtReceivedStamp;
	}

	public void setDocWithCourtReceivedStamp(Documents docWithCourtReceivedStamp) {
		this.docWithCourtReceivedStamp = docWithCourtReceivedStamp;
	}

	public Documents getDocWithDocketIdStamp() {
		return docWithDocketIdStamp;
	}

	public void setDocWithDocketIdStamp(Documents docWithDocketIdStamp) {
		this.docWithDocketIdStamp = docWithDocketIdStamp;
	}
}
